<script lang="ts">
import { debounce } from '@peng_kai/kit/libs/lodash-es';
import { useEventListener } from '@peng_kai/kit/libs/vueuse';
import GameLoading from './GameLoading.vue';
import { emitGamePM, SELF_GAME_IFRAME_ID, useOnGamePM } from './helpers';
import LiveChart from './LiveChart.vue';

function useForwardKeydownToIframe() {
  useEventListener(window, 'keydown', (ev) => {
    // 当聚焦可输入元素时，不转发
    if (['INPUT', 'TEXTEARE'].includes(document.activeElement?.nodeName ?? ''))
      return;

    // 当某些按键有默认行为时取消默认行为
    if (['Space'].includes(ev.code)) {
      ev.preventDefault();
      if (window.document.querySelectorAll('.ant-modal-mask:not([style])').length) {
        return;
      }
      else {
        window.document.querySelector('html')!.scrollTop = 0;
      }
    }

    emitGamePM.keydown({ code: ev.code, key: ev.key });
  });
}

function markCurrencyRefreshEmitedGame() {
  let is = false;
  let timer = -1;

  const mark = () => {
    is = true;
    clearTimeout(timer);
    timer = setTimeout(() => is = false, 1000);
  };

  const clear = () => {
    is = false;
    clearTimeout(timer);
  };

  return {
    get is() {
      return is;
    },
    mark,
    clear,
  };
}
</script>

<script setup lang="ts">
const props = defineProps<{
  url?: string;
}>();

const appStore = useAppStore();
const userState = useUserStore();
const currencyStore = useCurrencyStore();
const appSocket = useAppSocket();
const bp = useAppBreakpoints();
const $viewWrapper = ref<HTMLElement>();
const iframeHeight = ref<number>();
const isIFrameLoaded = ref(false);
const currencyRefreshEmitedGame = markCurrencyRefreshEmitedGame();

function refetchCurrencyBalance(currency?: string) {
  const finalCurrency = currency || currencyStore.cryptoName;

  if (!finalCurrency)
    return;

  appSocket.send('USER_BALANCE_REQ', 'BalanceResp', (data) => {
    data.Currency = finalCurrency;
    return data;
  });
}

currencyStore.refetch();
onBeforeRouteUpdate(currencyStore.refetch);
onBeforeRouteLeave(currencyStore.refetch);
useForwardKeydownToIframe();

watch(() => currencyStore.crypto, (newCrypto, oldCrypto) => {
  if (!newCrypto || !oldCrypto)
    return;

  if (currencyRefreshEmitedGame.is) {
    currencyRefreshEmitedGame.clear();
    return;
  }

  if (newCrypto.currency !== oldCrypto.currency) {
    emitGamePM.updateCurrency({ type: 'currency', currency: newCrypto.currency });
  }
  else if (newCrypto.balance !== oldCrypto.balance || newCrypto.bonus_balance !== oldCrypto.bonus_balance) {
    emitGamePM.updateCurrency({ type: 'balance', currency: newCrypto.currency });
  }
}, { deep: true, immediate: true });

watch(() => userState.userInfo?.level, (newV, oldV) => {
  if (newV !== undefined && oldV !== undefined && newV !== oldV)
    emitGamePM.updateUser();
});

useOnGamePM('updateBalance', () => {
  currencyRefreshEmitedGame.mark();
  currencyStore.refetch();
});

useOnGamePM('addMyLog', debounce((data) => {
  const currency = data?.currency;

  if (!currency)
    return;

  currencyRefreshEmitedGame.mark();

  // 暂时基于 addMyLog 事件做的余额请求,
  // 因为收到 addMyLog 事件时代表游戏以出结果（包含动画时间）
  refetchCurrencyBalance(currency);
}, 50, { maxWait: 500, leading: true, trailing: false }));
useOnGamePM('loaded', () => {
  isIFrameLoaded.value = true;
  emitGamePM.updateCurrency({
    type: 'init',
    currency: currencyStore.crypto!.currency,
  });
});
useOnGamePM('updateGameState', (data) => {
  appStore.hiddenBalanceReason = data.state === 'playing' ? 'Playing...' : '';
  data.state === 'idle' && refetchCurrencyBalance();
});
useOnGamePM('showGameRecord', data => globalPopups.gameRecordDetail.open(data));
useOnGamePM('deposit', () => globalPopups.wallet.open());
useOnGamePM('login', () => globalPopups.sign.open());
useOnGamePM('resetWinSize', (data) => {
  iframeHeight.value = data.height;
});
useOnGamePM('popupRect', (popupRect) => {
  const $view = $viewWrapper.value;

  if (!$view || bp.tablet)
    return;

  // view 距离页面顶部的固定距离
  const viewT = 64;
  // 减掉header和bottomNav的有效可视高度
  const viewH = window.outerHeight - 100;
  let offsetTop = 0;

  if (popupRect.height < viewH) {
    offsetTop = (viewT + popupRect.top + popupRect.height / 2) - (window.outerHeight / 2);
  }

  window.scrollTo({ top: offsetTop });
});
useOnGamePM('refresh', () => {
  appValues.refreshRoute?.();
});
</script>

<template>
  <!-- 粘性布局是为了阻止游戏内的动画暂停(游戏内部基于requestAnimationFrame的动画,如果页面不可见则会暂停) -->
  <div ref="$viewWrapper" class="sticky min-h-120" :style="{ top: `-${(iframeHeight ?? 0) - 40}px` }">
    <iframe
      :id="SELF_GAME_IFRAME_ID" :src="props.url"
      class="h-full w-full rounded-2 border-none bg-sys-layer-c outline-none"
      :style="{ height: `${iframeHeight}px` }"
    />
    <GameLoading v-if="!isIFrameLoaded" class="rounded-2" />
    <Teleport to="body">
      <LiveChart />
    </Teleport>
  </div>
</template>
